﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JpLabs.Geometry;

namespace Duellum.Map
{
	public static class DuelMapExt
	{
		static public IEnumerable<PointInt> GenerateRandomStartPositons(this DuelMap map, int count)
		{
			Random rnd = new Random();
			
			double dmin = Math.Sqrt((map.DimX+1) * (map.DimY+1) * (map.DimZ+1)) / (double)count;

			while (true)
			{
				//1. Generate one set of valid positions
				PointInt[] positionSet = Enumerable.Range(0, count).Select( i => RandomStartPostion(rnd, map) ).ToArray();
				
				//2. Verify if set is valid, i.e., minimum distance is acceptable
				if (MinimumDistance(positionSet) > dmin) return positionSet;
				
				//3. After each false attempt, decrease minimum distance slightly
				dmin *= 0.985;
				
				//4. If minimum distance gets too short, just give up
				if (dmin < Math.E) throw new InvalidOperationException("Unable to generate random start positions");
			}
		}
		
		private static PointInt RandomStartPostion(this Random rnd, DuelMap map)
		{
			const int MAX_ATTEMPTS = 512;
			
			for (int i=0; i<MAX_ATTEMPTS; i++)
			{
				var pos = new PointInt(
					rnd.Next(map.DimX + 1),
					rnd.Next(map.DimY + 1),
					rnd.Next(map.DimZ + 1)
				);
				
				//Check if position is valid
				var objs = map.Query(pos).ToArray();
				if (pos.Z == map.GroundLevel && !objs.Any()) return pos;
				if (pos.Z > map.GroundLevel && objs.WhereIsGround().Any() && !objs.WhereIsNotGround().Any()) return pos;
				//TODO: underground?
			}
			
			throw new ArgumentException("Not able to find an empty position in map", "map");
		}
		
		private static double MinimumDistance(this IEnumerable<PointInt> points)
		{
			var array = points.ToArray();
			
			var dists = array.SelectMany(
				(p,i) =>
				array
				.Where( (q,j) => j > i )
				.Select( q => (p - q).Length )
			);
			
			return dists.Min();
		}

	}
}
